/**
 * Copyright (c) Huawei Technologies Co., Ltd. 1987-2021. All rights reserved.
*/

package com.gitee.fufu669.config.redis;

import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.util.Assert;

import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;

/** @author wangfupeng */
/**
 * TODO
*/
public class CustomGenericJackson2JsonRedisSerializer implements RedisSerializer<Object> {

    // TODO
    private final ObjectMapper mapper;

    /**
     * Creates {@link CustomGenericJackson2JsonRedisSerializer} and configures {@link ObjectMapper} for default typing.
     */
    public CustomGenericJackson2JsonRedisSerializer() {
        // TODO
        this((String) null);
    }

    /**
     * Creates {@link CustomGenericJackson2JsonRedisSerializer} and configures {@link ObjectMapper} for default typing using the
     * given {@literal name}. In case of an {@literal empty} or {@literal null} String the default
     * {@link /**JsonTypeInfo.Id#CLASS} will be used.
     *
     * @param classPropertyTypeName Name of the JSON property holding type information. Can be {@literal null}.
     */
    public CustomGenericJackson2JsonRedisSerializer(String classPropertyTypeName) {
        // TODO
        this(new ObjectMapper());

        // 判断
        if (null!=classPropertyTypeName) {
            // TODO
            mapper.enableDefaultTypingAsProperty(DefaultTyping.NON_FINAL, classPropertyTypeName);
        // 否则
        } else {
            // TODO
            mapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY);
        }
    }

    /**
     * Setting a custom-configured {@link ObjectMapper} is one way to take further control of the JSON serialization
     * process. For example, an extended {@link /**SerializerFactory} can be configured that provides custom serializers for
     * specific types.
     * 
     * @param mapper must not be {@literal null}.
     */
    public CustomGenericJackson2JsonRedisSerializer(ObjectMapper mapper) {

        // TODO
        Assert.notNull(mapper, "ObjectMapper must not be null!");
        // 赋值
        this.mapper = mapper;
    }

    /**
     * (non-Javadoc)
     * @see org.springframework.data.redis.serializer.RedisSerializer#serialize(java.lang.Object)
     */
    @Override
    /**
     * TODO
    */
    public byte[] serialize(Object source) throws SerializationException {

        // 判断是否是空
        if (source == null) {
            // 返回
            return null;
        }

        // 尝试下面的代码
        try {
            // 返回
            return mapper.writeValueAsBytes(source);
        // 捕捉异常
        } catch (JsonProcessingException e) {
            // 抛出异常
            throw new SerializationException("Could not write JSON: " + e.getMessage(), e);
        }
    }

    /**
     * (non-Javadoc)
     * @see org.springframework.data.redis.serializer.RedisSerializer#deserialize(byte[])
     */
    @Override
    /**
     * TODO
    */
    public Object deserialize(byte[] source) throws SerializationException {
        // 返回
        return deserialize(source, Object.class);
    }

    /**
     * @param source can be {@literal null}.
     * @param type must not be {@literal null}.
     * @return {@literal null} for empty source.
     * @throws SerializationException
     */
    public <T> T deserialize(byte[] source, Class<T> type) throws SerializationException {

        // TODO
        Assert.notNull(type, 
                "Deserialization type must not be null! Pleaes provide Object.class to make use of Jackson2 default typing.");
        
        // 判断是否是空
        if(source==null) {
            // 返回
            return null;
        }
        
        // 判断
        if (source.length==0) {
            // 返回
            return null;
        }

        // 尝试下面的代码
        try {
            // 返回
            return mapper.readValue(source, type);
        // 捕捉异常
        } catch (Exception ex) {
            // 抛出异常
            throw new SerializationException("Could not read JSON: " + ex.getMessage(), ex);
        }
    }
}
